﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using LinqtoCRM.Tests.CRM;

namespace LinqtoCRM.Tests
{
    static class CrmExtensions
    {
        /// <summary>
        /// Extension method so that we can test using them in projections
        /// </summary>
        public static bool IsMerged(this contact c)
        {
            return c.merged.Value;
        }
    }

    [TestFixture]
    public class ProjectionTests : LinqtoCRMTests
    {
        [Test]
        public void TestMainEntity()
        {
            var contacts = from c in provider.Linq<contact>() select c;
            var first = contacts.AsEnumerable().First();
            Assert.AreEqual(first.firstname, "John");
        }

        [Test]
        public void TestIterateOverQuery()
        {
            var contacts = provider.Linq<contact>();
            Assert.AreEqual(2, contacts.AsEnumerable().Count());
        }

        [Test]
        public void TestObjectReference()
        {
            var contacts = from c in provider.Linq<contact>() select new { Value1 = c.gendercode, Value2 = c.gendercode };
            var first = contacts.AsEnumerable().First();
            // Value2 and Value1 should reference the same object
            Assert.AreSame(first.Value1, first.Value2);
        }

        [Test]
        public void TestAttributeRenaming()
        {
            CrmQueryProvider provider = new CrmQueryProvider(new DummyService("ProductsAndUOMs.xml"));

            var res = from pl in provider.Linq<productpricelevel>()
                      join pr in provider.Linq<product>() on pl.productid.Value equals pr.productid.Value
                      join uom in provider.Linq<uom>() on pl.uomid.Value equals uom.uomid.Value
                      select new
                      {
                          pr.name,
                          productid = pr.productid.Value,
                          producttypecode = pr.producttypecode,
                          productnumber = pr.productnumber,
                          uomname = uom.name,
                          uomid = uom.uomid.Value
                      };

            var first = res.AsEnumerable().First();

            Assert.AreEqual("testname", first.name);
            Assert.AreEqual(Guid.Empty, first.productid);
            Assert.AreEqual("Sales Inventory", first.producttypecode.name);
            Assert.AreEqual(1, first.producttypecode.Value);
            Assert.AreEqual("Perpetual", first.uomname);
            Assert.AreEqual("testnumber", first.productnumber);
            Assert.AreEqual(Guid.Empty, first.uomid);
        }

        [Test]
        public void TestJoinOnDifferentAttributeNames()
        {
            CrmQueryProvider provider = new CrmQueryProvider(new DummyService("ContactsWithParentAccounts.xml"));
            var res = from a in provider.Linq<account>()
                      join c in provider.Linq<contact>()
                      on a.accountid.Value equals c.parentcustomerid.Value
                      select new { a.name, c.fullname };
            Assert.AreEqual(3, res.AsEnumerable().Count());
            Assert.AreEqual("Account, 1", res.AsEnumerable().First().fullname);
        }

		[Test]
		public void TestMainEntityWithWhere()
		{
			var contacts = from c in provider.Linq<contact>() where c.firstname == "John" select c;
			var first = contacts.AsEnumerable().First();
			Assert.AreEqual(first.salutation, "Sir");
		}


        /// <summary>
        /// Issue #7221
        /// </summary>
        [Test]
        public void TestProjectNonexistantFields()
        {
            CrmQueryProvider provider = new CrmQueryProvider(new DummyService("DummyContactWithNonexistantFields.xml"));
            var contacts = from c in provider.Linq<contact>() where c.firstname == "John" select c;
            var first = contacts.AsEnumerable().First();
            
        }

        [Test]
        public void TestExtensionMethod()
        {
            var merged = from c in provider.Linq<contact>() select new { IsMerged = c.IsMerged() };
            Assert.IsFalse(merged.AsEnumerable().First().IsMerged);
        }

        [Test]
        public void TestDecimal()
        {
            CrmQueryProvider provider = new CrmQueryProvider(new DummyService("Decimals.xml"));
            var level = from p in provider.Linq<productpricelevel>() select p.amount;
            Assert.AreEqual(333.33, level.AsEnumerable().First().Value);
        }

        [Test]
        public void TestLookupName()
        {
            var contacts = from c in provider.Linq<contact>() select new { ModifiedBy = c.modifiedby.name };
            Assert.AreEqual("Administrator", contacts.AsEnumerable().First().ModifiedBy);
        }
    }
}
